package cn.xuqiudong.backend.base.exception;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.xuqiudong.common.base.model.BaseResponse;
import cn.xuqiudong.common.base.web.GlobalExceptionHandler;
import cn.xuqiudong.common.util.JsonUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.http.HttpStatus;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 描述:
 *
 * @author Vic.xu
 * @since 2025-02-05 17:24
 */
@ControllerAdvice
@ConditionalOnClass(HttpServletRequest.class)
public class ApiGlobalExceptionHandler extends GlobalExceptionHandler {


    /**
     * 捕获未登录异常
     * StpUtil.checkLogin()
     * 如果用户 Token 过期，而 未启用 "记住我" 机制，Token 会失效，导致 StpUtil.isLogin() 返回 false，进而抛出 NotLoginException。
     */
    @ExceptionHandler(NotLoginException.class)
    public ModelAndView handleNotLoginException(HttpServletRequest request, NotLoginException e) {
        BaseResponse<?> baseResponse = BaseResponse.error(401, "未登录，请先登录");
        return createModelAndView(request, baseResponse);
    }

    /**
     * 捕获权限异常
     * StpUtil.checkPermission()
     *
     * @see SaCheckPermission
     */
    @ExceptionHandler(NotPermissionException.class)
    public ModelAndView handleNotPermissionException(HttpServletRequest request, NotPermissionException e) {
        BaseResponse<?> baseResponse = BaseResponse.error(403, "权限不足");
        return createModelAndView(request, baseResponse);
    }

    /**
     * 捕获角色异常
     * StpUtil.checkRole("admin");
     *
     * @see SaCheckRole
     */
    @ExceptionHandler(NotRoleException.class)
    public ModelAndView handleNotRoleException(HttpServletRequest request, NotRoleException e) {
        BaseResponse<?> baseResponse = BaseResponse.error(403, "角色不足");
        return createModelAndView(request, baseResponse);
    }

    @ExceptionHandler(value = {Exception.class})
    public ModelAndView exceptionHandler(HttpServletRequest request, Exception e) {
        logger.error("非自定义异常", e);
        BaseResponse<?> baseResponse = BaseResponse.error(e.getMessage());
        return createModelAndView(request, baseResponse);
    }

    /**
     * 捕捉404
     * 但是spring 默认情况下不会触发 NoHandlerFoundException, 需要配置:
     * spring.mvc.throw-exception-if-no-handler-found=true
     * spring.web.resources.add-mappings=false
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ModelAndView handleNotFound(HttpServletRequest request,  NoHandlerFoundException e) {
        BaseResponse<?> baseResponse = BaseResponse.error(HttpStatus.NOT_FOUND.value(), HttpStatus.NOT_FOUND.getReasonPhrase());
        return createModelAndView(request, baseResponse);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ModelAndView handleMethodNotSupported(HttpServletRequest request,  HttpRequestMethodNotSupportedException e) {
        BaseResponse<?> baseResponse = BaseResponse.error(HttpStatus.METHOD_NOT_ALLOWED.value(), HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase());
        return createModelAndView(request, baseResponse);
    }

    @Override
    protected ModelAndView createModelAndView(HttpServletRequest request, BaseResponse<?> baseResponse) {
        ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
//            modelAndView.addObject(baseResponse);
        modelAndView.addAllObjects(JsonUtil.OBJECT_MAPPER.convertValue(baseResponse, Map.class));
        return modelAndView;

    }
}
